import url from "url";
import { getIp } from "../helper/ip.js";

// 改进的关键词列表，区分需要全词匹配的关键词
const keywords = {
  // 需要全词匹配的关键词（避免短词误报）
  wholeWord: [
    // 系统命令/工具（容易产生短词误报）
    "opt", "cmd", "rm", "mdc", "netcat", "nc", "mdb", "bin", "mk", "sys","sh","chomd",
    "php-cgi","process","require","child_process","execSync","mainModule"
  ],
  
  // 普通关键词（包含特殊字符或较长关键词）
  normal: [
    // 文件扩展名 & 敏感文件
    ".php", ".asp", ".aspx", ".jsp", ".jspx", ".do", ".action", ".cgi", 
    ".py", ".pl", ".md", ".log", ".conf", ".config", ".env", ".jsa",  
    ".go", ".jhtml", ".shtml", ".cfm", ".svn", ".keys", ".hidden", 
    ".bod", ".ll", ".backup", ".json", ".xml", ".bak", ".aws", 
    ".database", ".cookie", ".rsp", ".old", ".tf", ".sql", ".vscode", 
    ".docker", ".map", ".save", ".gz", ".yml", ".tar", ".sh", ".idea", ".s3",

    // 敏感目录
    "/administrator", "/wp-admin", 

    // 高危路径/应用
    "phpMyAdmin", "setup", "wp-", "cgi-bin", "xampp", "staging", "internal",
    "debug", "metadata", "secret", "smtp",  "redirect", "configs",

    // SQL 注入
    "sleep(", "benchmark(", "concat(", "extractvalue(", "updatexml(",
    "version(", "union select", "union all", "select @@", "drop",
    "alter", "truncate", "exec", "(select", "information_schema",
    "load_file(", "into outfile", "into dumpfile",

    // 命令注入
    "cmd=", "system(", "exec(", "shell_exec(", "passthru(", "base64_decode",
    "eval(", "assert(", "preg_replace", "bash -i", "rm -rf", "wget ", "curl ",
    "chmod ", "phpinfo()",

    // 路径遍历
    "../", "..\\", "/etc/passwd", "/etc/shadow",

    // XSS
    "<script", "javascript:", "onerror=", "onload=", "alert(", "document.cookie",

    // 特殊编码
    "0x7e", "UNION%20SELECT", "%27OR%27", "{{", "}}", "1+1"
  ]
};

// === 预处理：构建正则缓存 ===
const { wholeWordRegexCache, normalRegexCache } = (() => {
  const regexSpecialChars = /[.*+?^${}()|[\]\\]/g;
  const wholeWordRegexCache = {};
  const normalRegexCache = {};

  // 处理需要全词匹配的关键词
  keywords.wholeWord.forEach((keyword) => {
    // 转义特殊字符
    const escaped = keyword.replace(regexSpecialChars, "\\$&");
    // 使用单词边界确保全词匹配，忽略大小写
    wholeWordRegexCache[keyword] = new RegExp(`\\b${escaped}\\b`, "i");
  });

  // 处理普通关键词
  keywords.normal.forEach((keyword) => {
    // 转义特殊字符
    const escaped = keyword.replace(regexSpecialChars, "\\$&");
    // 普通匹配，忽略大小写
    normalRegexCache[keyword] = new RegExp(escaped, "i");
  });

  return { wholeWordRegexCache, normalRegexCache };
})();

/**
 * WAF 安全中间件（优化版，减少误报）
 */
const safe = (req, res, next) => {
  try {
    const { WAF_LEVEL = 1 } = Chan.config || {};

    // 设置基础安全头
    res.setHeader("X-Content-Type-Options", "nosniff");
    res.setHeader("X-XSS-Protection", "1; mode=block");
    res.setHeader("X-Frame-Options", "DENY");

    // 构建检测文本：path + query + body
    let checkText = req.path || "";

    // 添加 query
    if (req.query && Object.keys(req.query).length > 0) {
      const queryStr = Object.entries(req.query)
        .map(([k, v]) => `${k}=${v}`)
        .join(" ");
      checkText += ` ${queryStr}`;
    }

    // 添加 body（非 multipart）
    let bodyText = "";
    const contentType = req.headers["content-type"] || "";
    const isMultipart = contentType.includes("multipart/form-data");

    if (!isMultipart && req.body) {
      try {
        const bodyStr =
          typeof req.body === "string" ? req.body : JSON.stringify(req.body);
        // 限制检测的body长度，避免性能问题
        if (bodyStr.length < 10000) {
          bodyText = ` ${bodyStr}`;
        }
      } catch (e) {
        // 忽略序列化错误
      }
    }

    const fullText = checkText + bodyText;
    
    // 空文本直接跳过检测
    if (!fullText.trim()) return next();

    let matchedKeyword = null;

    // 1. 检测需要全词匹配的关键词
    for (const [kw, regex] of Object.entries(wholeWordRegexCache)) {
      if (regex.test(fullText)) {
        matchedKeyword = kw;
        break;
      }
    }

    // 2. 检测普通关键词
    if (!matchedKeyword) {
      for (const [kw, regex] of Object.entries(normalRegexCache)) {
        if (regex.test(fullText)) {
          matchedKeyword = kw;
          break;
        }
      }
    }

    // === 拦截处理 ===
    if (matchedKeyword) {
      const clientIp = getIp(req);
      const userAgent = req.get("User-Agent") || "";

      console.error("[WAF 拦截] 疑似恶意请求:", {
        url: req.url,
        ip: clientIp,
        userAgent: userAgent.substring(0, 100),
        method: req.method,
        matchedKeyword,
        sample: fullText.substring(0, 200) + (fullText.length > 200 ? "..." : ""),
      });

      // 根据WAF级别决定拦截方式
      if (WAF_LEVEL >= 2) {
        return res.status(403).send("非法风险请求，已拦截");
      } else {
        // 低级别仅记录不拦截，便于观察误报
        console.warn("[WAF 警告] 低级别模式下未拦截请求");
        return next();
      }
    }

    next();
  } catch (error) {
    console.error("[WAF 异常]", error);
    res.status(500).send("服务器内部错误");
  }
};

/**
 * 导出 WAF
 */
export const waf = (app) => {
  app.use(safe);
};
